# ===================================================================================
# EXTERNAL FUNCTIONS
# ===================================================================================  

# ------------------------------------
# Cancel the installation process
# ------------------------------------ 
Function Abort-Installation ( [string] $pAbort )
{
	if ( ($pAbort -eq $null) -or ($pAbort.ToLower() -ne "y" ) )
	{
		Write-Host -ForegroundColor Yellow  ">> Aborting Installation .." 
		exit
	}
}

# ------------------------------------
# Check Buildversion
# ------------------------------------    
Function Check-BuildVersion( [string] $pBuildVersion )
{
	if ( $pBuildVersion -eq "")
	{
		Write-Host -ForegroundColor Red  " > No -BuildVersion parameter found. Enter the version of the new CU as parameter (e.g -BuildVersion `"15.0.4535.1000`")" 
		Exit
	}

	$currentBuild = (Get-SPFarm).BuildVersion.ToString()
	Write-Host -ForegroundColor Yellow  " > Current Buildnumber is: $currentBuild" 
	Write-Host -ForegroundColor Yellow  " > New Buildnumber is    : $pBuildVersion" 

	$currentBuild  = $currentBuild.Replace(".", "")
	$pBuildVersion = $pBuildVersion.Replace(".", "")

	if ( $currentBuild -ge $pBuildVersion )
	{
		Write-Host -ForegroundColor Red  " > This CU is already installed on this server." 		
		Abort-Installation
	}
}

# ------------------------------------
# Check If Current User is Farm Admin
# ------------------------------------    
Function Check-FarmAdminAccount
{
	$curLogin     = $env:username
	$farmAccount  = (Get-SPFarm).DefaultServiceAccount.Name
	$farmAccParts = $farmAccount.Split("\")
	$farmLogin    = ""
	if ( $farmAccParts.Length -gt 1) 
	{
		$farmLogin = $farmAccParts[1]
	}
	else
	{
		$farmLogin = $farmAccParts[0]
	}
	
	Write-Host 
	Write-Host -ForegroundColor Yellow  ">> Cheking if loggedin user is farm admin." 
	Write-Host -ForegroundColor Yellow  " > Loggedin user: " $curLogin  
	Write-Host -ForegroundColor Yellow  " > Farm admin   : " $farmLogin

	if ( $curLogin -ne $farmLogin )
	{
		Write-Host -ForegroundColor Red  " > The current user is not the default farm account." 
		Write-Host -ForegroundColor Red  " > Do you want to proceed anyway? [Y/N]" 
		$doContinue = Read-Host
		Abort-Installation $doContinue
	}
	else
	{
		Write-Host -ForegroundColor Green  " > Account is Farm Account." 
	}
}

# ------------------------------------
# Check which version of SharePoint 
# is installed.
# ------------------------------------    
Function Check-SPVersion
{
	Write-Host -ForegroundColor Yellow  ">> Cheking for SharePoint version..." 
	$version = (Get-SPFarm).BuildVersion.Major
	if ($version -eq 14)
	{
		Write-Host -ForegroundColor Green  " > Found SharePoint 2010." 
		return $version
	}
	elseif($version -eq 15)
	{
		Write-Host -ForegroundColor Green  " > Found SharePoint 2013." 
		return $version
	}
	else
	{
		Write-Host -ForegroundColor Red  " > Either you don't run the script in a SharePoint Management Shell or you don't have SharePoint installed on this server." 
		Abort-Installation
	}
}

# ------------------------------------
# Check if console is running in admin
# mode
# ------------------------------------ 
Function Check-IsAdminMode
{
	Write-Host
	Write-Host -ForegroundColor Yellow ">> Cheking if Console is running in admin mode..."
	
	$wid = [System.Security.Principal.WindowsIdentity]::GetCurrent()
	$prp = New-Object System.Security.Principal.WindowsPrincipal($wid)
	$adm = [System.Security.Principal.WindowsBuiltInRole]::Administrator
	$isAdmin = $prp.IsInRole($adm)
	
	if ($isAdmin -eq $false)
	{
		Write-Host -ForegroundColor Red  " > Run the SharePoint Management Shell in Admin Mode. (Runas Administrator)" 
		Abort-Installation
	}
	
	Write-Host -ForegroundColor Green " > O.K."
}
  
# ------------------------------------
# Checks if the Patch is in folder and
# returns it filename.
# ------------------------------------
Function Ensure-PackageExists ( [string] $pPathToPatch )
{
	$found = $false;
	Write-Host -ForegroundColor Yellow  ">> Searching for the Cumulative Update...." 
	if ( $pPathToPatch -eq "" )
	{
		$patchfile = Get-ChildItem | where {$_.Extension -eq ".exe"} 
		if($patchfile -ne $null) 
		{ 
			Write-Host -ForegroundColor Green  " > Found: " $patchfile.basename 
			return $patchfile.basename
		}		
	}
	
	if (Test-Path ($pPathToPatch))
	{
		Write-Host -ForegroundColor Green  " > Found: " $pPathToPatch
		return $pPathToPatch
	}
	
	Write-Host -ForegroundColor Red  " > ERROR: Unable to retrieve the CU file.`n"
	Write-Host -ForegroundColor Red  " > Either place one .exe file into the same folder or give the path to the update file as parameter.`n Exiting Script." 
	exit
}

# ------------------------------------
# Stops a window service
# ------------------------------------
Function Stop-WindowsService ([string] $pServiceName)
{	
	try
	{			
		# STOP SERVICE
		Write-Host
		Write-Host  -ForegroundColor yellow ">> Stopping Service $pServiceName ..." 	
		$winSvc = Get-Service $pServiceName 
		if($winSvc.status -eq "Running") 
		{
			$winSvc.stop()			
		}
		else
		{
			Write-Host -ForegroundColor magenta "  > The Service $pServiceName is not running." 
		}	
		
		Write-Host -ForegroundColor Yellow "  > Checking if Service really stopped ..."
		Write-Host "   " -NoNewline 
		$i = 0
		$delay = 60
		do { 
			$winSvc = Get-Service $pServiceName 
			Start-Sleep -seconds 5 
			Write-Host -ForegroundColor Green "*" -NoNewline 
			$i++
		} until ( ($winSvc.status -eq "Stopped")-or ($i -gt $delay) ) 	
			
		if ($i -gt $delay)
		{
			Write-Host -ForegroundColor Red " Could not stop $pServiceName. Try it to stop manually."
			exit
		}
		else
		{		
			Write-Host -ForegroundColor Green " Service stopped."
		}
		
		# DISABLE SERVICE
		$startMode = (Get-WmiObject Win32_Service -filter "Name='$pServiceName'").StartMode				
		Write-Host -ForegroundColor yellow ">> Disabling Service $pServiceName ..." 	
		Write-Host -ForegroundColor yellow "  > Startmode of service is: $startMode" 	
		
		if ($startMode -ne "Disabled")
		{			
			Set-Service -Name $pServiceName -startuptype Disabled 
			Write-Host -ForegroundColor green "  > Disabled." 
		}
		else
		{
			Write-Host -ForegroundColor magenta "  > The Service $pServiceName is already disabled." 
		}
	}
	catch [System.Exception]
	{		
		Write-Host -ForegroundColor red "  > Error: An exception occured while stopping the Service $pServiceName." 		
		Write-Host -ForegroundColor red "  > Stopping installation.`n" 		
		$_.Exception.ToString();
		
		Exit
	}
}

# ------------------------------------
# Start patching
# ------------------------------------
Function Start-Patching ([string]$pPatchFileName)
{
	Write-Host -ForegroundColor Magenta ">> Patching now keep this PowerShell window open ..." 

	$startTime = Get-Date
	$arg       = "/passive"

	Start-Process $pPatchFileName $arg
	Start-Sleep -Seconds 20 
	try
	{
		$proc = Get-Process $pPatchFileName 
		$proc.WaitForExit()
	}
	catch [System.Exception] 
	{
		Write-Host -ForegroundColor red    "  > Could not get the installation process."  
		Write-Host -ForegroundColor yellow "  > This can happen if you use a network path."  
		Write-Host -ForegroundColor yellow "  > Just press any key to continue after the installation is complete."  
		Read-Host
	}

	$finishTime = Get-Date 
		
	$diff = $finishTime - $startTime
	Write-Host -ForegroundColor yellow " > Patch Installation Duration:"
	Write-Host -ForegroundColor yellow "  - Started : " $startTime 
	Write-Host -ForegroundColor yellow "  - Finished: " $finishtime
	Write-Host
	
	if ($diff.Minutes -lt 2)
	{
		Write-Host -ForegroundColor red "  > The duration of teh installation was under 2 minutes."
		Write-Host -ForegroundColor red "  > Possible reasons can be:"
		Write-Host -ForegroundColor red "    - The installed patch is wrong."
		Write-Host -ForegroundColor red "    - The installed patch needs another previous patch like SP1 or SP2."
		Write-Host
		Write-Host -ForegroundColor red "  > Start the patch manually to see the error."
		$global:doRestart = $false
	}
	else	
	{
		Write-Host -ForegroundColor green "  > Patch installation complete."
	}
}
 
# ------------------------------------
# Start Service
# ------------------------------------
Function Start-WindowsService([string] $pServiceName)
{			
	Write-Host
	$startMode = (Get-WmiObject Win32_Service -filter "Name='$pServiceName'").StartMode				
	Write-Host -ForegroundColor yellow ">> Setting Service '$pServiceName' to automatic startup ..." 	
	Write-Host -ForegroundColor yellow "  > Startmode of service is: $startMode" 	
	
	if ($startMode -eq "Disabled")
	{			
		Set-Service -Name $pServiceName -startuptype Automatic 
		Write-Host -ForegroundColor green "  > Done." 
	}
	else
	{
		Write-Host -ForegroundColor magenta "  > The Service $pServiceName is already enabled." 
	}
	
	Write-Host -ForegroundColor yellow ">> Starting '$pServiceName' Service." 
	$svc = Get-Service $pServiceName 
	if($svc.Status -eq "Stopped") 
	{ 		
		$svc.Start() 
		Write-Host -ForegroundColor green "  > Done." 
	}
	else
	{
		Write-Host -ForegroundColor magenta "  > The Service $pServiceName is already running."
	}
}

# ------------------------------------
# Creates the registry entry so
# that after restart the SP Config 
# Wizard starts.
# ------------------------------------
Function Create-AutorunKey
{	
	$script = Join-Path (Split-Path $SCRIPT:MyInvocation.MyCommand.Path -parent) $SCRIPT:MyInvocation.MyCommand.Name	
	$script	= $script.Replace(" ", "`` ")
		
	Set-ItemProperty -Path $global:regRunKey -Name $global:restartKey -Value "$global:powershell `"$script -RunWizard:`$true`""
	
	if ( (Test-Path $global:regRunKey) -and ( (Get-ItemProperty $global:regRunKey).$global:restartKey -ne $null ) ) 
	{
		Write-Host -ForegroundColor Green  "  > Autostart entry created." 
	}
	else
	{
		Write-Host -ForegroundColor Red  "  > Autostart enty could not be created. Start the SharePoint Configuration Wizard after reboot manually." 
		Write-Host -ForegroundColor Red  "  > Press any key to reboot." 
		Read-Host
	}
}

# ------------------------------------
# Check if its a restart
# if so start the SharePoint Config
# Manager
# ------------------------------------
Function Start-ConfigurationWizard( [boolean] $pDoStart, [string] $pPathToPSConfig)
{
	$psCfgCmd 	  = "psconfig.exe"
	$psCfgCmdArgs = "-cmd upgrade -inplace b2b -force -wait"
	
	if ($pDoStart -eq $true)
	{
		#Refresh list of updates on server		
		Get-SPProduct -local 
		
		#Remove Startup Keys from Registry
		Write-Host -ForegroundColor Yellow  ">> Is Restart. Removing Autostart keys.." 
		if ( (Test-Path $global:regRunKey) -and ( (Get-ItemProperty $global:regRunKey).$global:restartKey -ne $null ) ) 
		{        
			Remove-ItemProperty -path $global:regRunKey -name $global:restartKey
			
			if ( (Test-Path $global:regRunKey) -and ( (Get-ItemProperty $global:regRunKey).$global:restartKey -ne $null ) ) 
			{
				Write-Host -ForegroundColor Red  "  > Could not delete keys. Check if your acccount has enough rights." 
			}
			else
			{
				Write-Host -ForegroundColor Green  "  > Autostart keys removed." 
			}
		}
		else
		{
			Write-Host -ForegroundColor Yellow  "  > Could not find key." 
		}
		
		# Start SharePoint Configuration Wizard
		Write-Host -ForegroundColor Yellow  ">> Starting SharePoint Configuration Wizard Command Line ..." 
		$path = (Join-Path $pPathToPSConfig $psCfgCmd)
		
		$proc = Start-Process $path -ArgumentList $psCfgCmdArgs.Split(" ") -NoNewWindow
		$proc = Get-Process "PSCONFIG" 
		$proc.WaitForExit()
		
		Write-Host
		Write-Host -ForegroundColor Green   ">> Script finished." 		
		Write-Host -ForegroundColor Yellow  ">> On error, you can restart the config wizard with the following command." 		
		Write-Host -ForegroundColor Yellow  ">> Open PowerShell with <Run as Administrator>." 		
		Write-Host -ForegroundColor Magenta "   ./SP2013_CUInstaller_Main -IsRestart:$true -StartConfigUI:[$false|$true]" 		
		Write-Host
		Write-Host -ForegroundColor Yellow  ">> Press any key to exit."
		Read-Host
		exit
	}
}


# ------------------------------------
# Starts the current script
# with elevated priviliges
# ------------------------------------
Function Run-AsAdministrator ([boolean] $pRunWizard)
{
	if ($pRunWizard -eq $true)
	{
		$script = Join-Path (Split-Path $SCRIPT:MyInvocation.MyCommand.Path -parent) $SCRIPT:MyInvocation.MyCommand.Name  
		$script	= $script.Replace(" ", "`` ")	
		Start-Process "$powershell" "$script -IsRestart:`$true" -Verb runAs
		exit
	}
}
